package arithmetic.leetCode;

import java.util.List;

/*
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢？

注意：给定 n 是一个正整数。

示例 1：

输入： 2
输出： 2
解释： 有两种方法可以爬到楼顶。
1.  1 阶 + 1 阶
2.  2 阶
示例 2：

输入： 3
输出： 3
解释： 有三种方法可以爬到楼顶。
1.  1 阶 + 1 阶 + 1 阶
2.  1 阶 + 2 阶
3.  2 阶 + 1 阶

来源：力扣（LeetCode）
链接：https://leetcode-cn.com/problems/climbing-stairs
著作权归领扣网络所有。商业转载请联系官方授权，非商业转载请注明出处。
 */
public class ClimbStairs_70 {

    public static void main(String[] args) {
        ClimbStairs_70 climbStairs_70 = new ClimbStairs_70();
//        System.out.println(climbStairs_70.climbStairs2(44));
        System.out.println(climbStairs_70.climbStairs3(70));
        System.out.println(climbStairs_70.climbStairs(70));
    }


    /**
     * 方法三：动态规划
     * <p>
     * 算法
     * <p>
     * 不难发现，这个问题可以被分解为一些包含最优子结构的子问题，即它的最优解可以从其子问题的最优解来有效地构建，我们可以使用动态规划来解决这一问题。
     * <p>
     * 第 ii 阶可以由以下两种方法得到：
     * <p>
     * 在第 (i-1)(i−1) 阶后向上爬一阶。
     * <p>
     * 在第 (i-2)(i−2) 阶后向上爬 22 阶。
     * <p>
     * 所以到达第 ii 阶的方法总数就是到第 (i-1)(i−1) 阶和第 (i-2)(i−2) 阶的方法数之和。
     * <p>
     * 令 dp[i]dp[i] 表示能到达第 ii 阶的方法总数：
     * <p>
     * dp[i]=dp[i-1]+dp[i-2]
     * dp[i]=dp[i−1]+dp[i−2]
     * <p>
     * 作者：LeetCode
     * 链接：https://leetcode-cn.com/problems/climbing-stairs/solution/pa-lou-ti-by-leetcode/
     * 来源：力扣（LeetCode）
     * 著作权归作者所有。商业转载请联系作者获得授权，非商业转载请注明出处。
     *
     * @param n
     * @return
     */
    public int climbStairs(int n) {
        if (n == 1) {
            return 1;
        }
        int[] dps = new int[n + 1];
        dps[1] = 1;
        dps[2] = 2;

        for (int i = 3; i <= n; i++) {
            dps[i] = dps[i - 1] + dps[i - 2];
        }
        return dps[n];
    }

    /**
     * 方法四：斐波那契数
     * <p>
     * 算法
     * <p>
     * 在上述方法中，我们使用 dpdp 数组，其中 dp[i]=dp[i-1]+dp[i-2]dp[i]=dp[i−1]+dp[i−2]。可以很容易通过分析得出 dp[i]dp[i] 其实就是第 ii 个斐波那契数。
     * <p>
     * Fib(n)=Fib(n-1)+Fib(n-2)
     * Fib(n)=Fib(n−1)+Fib(n−2)
     * <p>
     * 现在我们必须找出以 11 和 22 作为第一项和第二项的斐波那契数列中的第 nn 个数，也就是说 Fib(1)=1Fib(1)=1 且 Fib(2)=2Fib(2)=2。
     * <p>
     * 作者：LeetCode
     * 链接：https://leetcode-cn.com/problems/climbing-stairs/solution/pa-lou-ti-by-leetcode/
     * 来源：力扣（LeetCode）
     * 著作权归作者所有。商业转载请联系作者获得授权，非商业转载请注明出处。
     *
     * @param n
     * @return
     */

    public int climbStairs3(int n) {
        if (n == 1 || n == 2) {
            return n;
        }
        int res = 2, prePre = 1, curr = 3;
        while (curr <= n) {
            int t = res + prePre;
            prePre = res;
            res = t;
            curr++;
        }
        return res;
    }


    /**
     * 递归超时
     *
     * @param n
     * @return
     */
    public int climbStairs2(int n) {
        if (n == 1 || n == 2) {
            return n;
        }
        return climbStairs2(n - 1) + climbStairs2(n - 2);
    }
}
